!! Copyright (C) 2009,2010,2011,2012  Marco Restelli
!!
!! This file is part of:
!!   FEMilaro -- Finite Element Method toolkit
!!
!! FEMilaro is free software; you can redistribute it and/or modify it
!! under the terms of the GNU General Public License as published by
!! the Free Software Foundation; either version 3 of the License, or
!! (at your option) any later version.
!!
!! FEMilaro is distributed in the hope that it will be useful, but
!! WITHOUT ANY WARRANTY; without even the implied warranty of
!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
!! General Public License for more details.
!!
!! You should have received a copy of the GNU General Public License
!! along with FEMilaro; If not, see <http://www.gnu.org/licenses/>.
!!
!! author: Marco Restelli                   <marco.restelli@gmail.com>

!>\brief
!!
!! Dummy version of \c mod_pastixintf to avoid linking PaStiX.
!!
!! \n
!!
!! The constructor, destructor and clean functions can be called,
!! while the remaining functions return an error. The use statements
!! are the same as in the true module, to simplify debugging and
!! testing with and without PaStiX.
!<----------------------------------------------------------------------
module mod_pastixintf

!-----------------------------------------------------------------------

 use mod_utils, only: &
   t_realtime, my_second

 use mod_messages, only: &
   mod_messages_initialized, &
   error,   &
   warning, &
   info

 use mod_kinds, only: &
   mod_kinds_initialized, &
   wp

 use mod_sparse, only: &
   mod_sparse_initialized, &
   ! sparse types
   t_col, t_tri,&
   col2tri,     &
   transpose,   &
   clear

 use mod_mpi_utils, only: &
   mod_mpi_utils_initialized

 use mod_state_vars, only: &
   mod_state_vars_initialized, &
   c_stv

 use mod_output_control, only: &
   mod_output_control_initialized, &
   elapsed_format, base_name

 use mod_linsolver_base, only: &
   mod_linsolver_base_initialized, &
   c_linpb

!-----------------------------------------------------------------------

 implicit none

!-----------------------------------------------------------------------

! Module interface

 public :: &
   mod_pastixintf_constructor, &
   mod_pastixintf_destructor,  &
   mod_pastixintf_initialized, &
   c_pastixpb

 private

!-----------------------------------------------------------------------

 ! For the real PaStiX library, these kinds are defined in the include
 ! file.
 integer :: m_int
 real    :: m_real
 integer, parameter :: mik = kind(m_int)
 integer, parameter :: mrk = kind(m_real)

 type, extends(c_linpb), abstract :: c_pastixpb
  logical :: transposed_mat = .false.
  integer :: gn
  type(t_col), pointer :: m
  integer, pointer :: gij(:)
  real(wp), pointer :: rhs(:)
  integer :: mpi_comm
  integer(mik), private :: nloc
  integer(mik), private, allocatable :: c_gij(:)
  integer(mik), private :: sol_ins
  logical, private :: sys_set   = .false.
  logical, private :: coeff_set = .false.
  logical, private :: rhs_set   = .false.
 contains
  procedure, pass(s) :: factor => pastix_factor
  procedure, pass(s) :: solve  => pastix_solve
  procedure, pass(s) :: clean  => pastix_clean
  procedure, nopass :: working_implementation => pastix_wi
  procedure(i_xassign), deferred, pass(s) :: xassign
 end type c_pastixpb

 abstract interface
  subroutine i_xassign(x,s,pastix_x)
   import :: wp, c_stv, c_pastixpb
   implicit none
   real(wp),         intent(in) :: pastix_x(:)
   class(c_pastixpb), intent(inout) :: s
   class(c_stv),     intent(inout) :: x
  end subroutine i_xassign
 end interface

 logical, protected ::               &
   mod_pastixintf_initialized = .false.
 character(len=*), parameter :: &
   errormsg = &
     'This is not a real PaStiX interface and should not be called.'
 character(len=*), parameter :: &
   this_mod_name = 'mod_pastixintf'

!-----------------------------------------------------------------------

contains

!-----------------------------------------------------------------------

 subroutine mod_pastixintf_constructor()

  integer(mik) :: ierr
  character(len=*), parameter :: &
    this_sub_name = 'constructor'

   !Consistency checks ---------------------------
   if( (mod_messages_initialized.eqv..false.) .or. &
          (mod_kinds_initialized.eqv..false.) .or. &
         (mod_sparse_initialized.eqv..false.) .or. &
      (mod_mpi_utils_initialized.eqv..false.) .or. &
 (mod_output_control_initialized.eqv..false.) .or. &
 (mod_linsolver_base_initialized.eqv..false.) ) then
     call error(this_sub_name,this_mod_name, &
                'Not all the required modules are initialized.')
   endif
   if(mod_pastixintf_initialized.eqv..true.) then
     call warning(this_sub_name,this_mod_name, &
                  'Module is already initialized.')
   endif
   !----------------------------------------------

   mod_pastixintf_initialized = .true.
 end subroutine mod_pastixintf_constructor

!-----------------------------------------------------------------------
 
 subroutine mod_pastixintf_destructor()

  integer(mik) :: ierr
  character(len=*), parameter :: &
    this_sub_name = 'destructor'
   
   !Consistency checks ---------------------------
   if(mod_pastixintf_initialized.eqv..false.) then
     call error(this_sub_name,this_mod_name, &
                'This module is not initialized.')
   endif
   !----------------------------------------------

   mod_pastixintf_initialized = .false.
 end subroutine mod_pastixintf_destructor

!-----------------------------------------------------------------------

  pure function pastix_wi()
   logical :: pastix_wi
    pastix_wi = .false.
  end function pastix_wi

!-----------------------------------------------------------------------


 subroutine pastix_factor(s,phase)
  class(c_pastixpb), intent(inout) :: s
  character(len=*), intent(in), optional :: phase
 
  character(len=*), parameter :: &
    this_sub_name = 'pastix_factor'

   call error(this_sub_name,this_mod_name,errormsg)

 end subroutine pastix_factor

!-----------------------------------------------------------------------

 subroutine pastix_solve(x,s)
  class(c_pastixpb), intent(inout) :: s
  class(c_stv),     intent(inout) :: x

  character(len=*), parameter :: &
    this_sub_name = 'pastix_solve'
 
   call error(this_sub_name,this_mod_name,errormsg)

 end subroutine pastix_solve

!-----------------------------------------------------------------------
 
 subroutine pastix_clean(s)
  class(c_pastixpb), intent(inout) :: s

  character(len=*), parameter :: &
    this_sub_name = 'pastix_clean'

 end subroutine pastix_clean

!-----------------------------------------------------------------------
 
end module mod_pastixintf

